#include "assert.h"
#include "mmu.h"
#include "proc.h"
#include "stddef.h"
#include "trap.h"
#include "lock/wait.h"

#include "lock/semaphore.h"

void
semaphore_init(semaphore_t* sem, int value) {
    sem->value = value;
    waitQueue_init(&(sem->waitQueue));
}

void
__semaphore_release(semaphore_t* sem, uint32_t waitState) {
    // intr_off();
    {
        wait_t* wait = waitQueue_first(&(sem->waitQueue));
        if (wait == NULL)
            ++sem->value;
        else {
            assert(wait->proc->state = SLEEPING);  // TODO
            wakeup_wait(&(sem->waitQueue), wait, waitState, 1);
        }
    }
    // intr_on();
    intr_pop();  // TODO 正确的信号量应当如何实现
}

uint32_t
__semaphore_acquire(semaphore_t* sem, uint32_t waitState) {  // TODO 正确的信号量应当如何实现
    // intr_off();
    intr_push();
    if (sem->value > 0) {
        --sem->value;
        intr_on();
        return 0;
    }
    wait_t wait;
    wait_current_set(&(sem->waitQueue), &wait, waitState);
    intr_on();

    sched();

    intr_off();
    wait_current_del(&(sem->waitQueue), &wait);
    intr_on();

    if (wait.wakeupFlags != waitState)
        return wait.wakeupFlags;
    return 0;
}

void
semaphore_release(semaphore_t* sem) {
    __semaphore_release(sem, WT_KSEM);
}

void
semaphore_acquire(semaphore_t* sem) {
    assert(__semaphore_acquire(sem, WT_KSEM) == 0);
}

/**
 * @brief
 *
 * @param sem
 * @return 0 - not get, 1 - get
 */
bool
semaphore_tryAcquire(semaphore_t* sem) {
    bool ret = 0;
    intr_off();
    if (sem->value > 0) {
        --sem->value;
        ret = 1;
    }
    intr_on();
    return ret;
}